import { defineStore } from 'pinia'
import $axios from "../plugins/http"
import { Base64 } from "js-base64"

export const useMessagePinia = defineStore('messages', {
  state: () => ({
    // 用户当前的聊天消息列表
    chatList: new Map() as Map<string, ChatList>,
    // 是否请求消息聊天列表结束
    isRequChatLisFinsh: false,
    // 对方是否正在输入
    isInputing: false,
    // 是否发送了图片消息
    isSendImg: false,
  }),
  getters: {
    // 用户未读的消息数
    unReadMessCouAll(): number {
      return [...this.chatList.values()]
        .reduce((previouse, current) => previouse + current.LatestMessInfo.unReadMessCou, 0);
    },
  },
  actions: {
    // 请求详细的消息记录(第一次请求)
    async getPartMessagesInit(payload: { userId: string, isHaveWindow: boolean }): Promise<number> {
      return await $axios(
        ['/messages/getPartMessagesInit', 'post', payload, true],
        ({ messagesList, isLast, LatestMessInfo }) => {
          if (!payload.isHaveWindow) {
            const chatList = [...this.chatList];
            if (LatestMessInfo.isTopping)
              chatList.unshift([payload.userId, {
                LatestMessInfo,
                messagesDatas: new Map(),
                isRequMessRecord: false,
                isNodisplayLoading: false,
                isToppingLoading: false,
              }]);
            else {
              const index: number = chatList.findIndex(item => !item[1].LatestMessInfo.isTopping);
              chatList.splice(index, 0, [payload.userId, {
                LatestMessInfo,
                messagesDatas: new Map(),
                isRequMessRecord: false,
                isNodisplayLoading: false,
                isToppingLoading: false,
              }]);
            }
            this.chatList = new Map(chatList);
          }
          const data = this.chatList.get(payload.userId)!;
          Object.assign(data, {
            messagesDatas: new Map(messagesList),
            isLast,
            isRequMessRecord: true,
            editMessage: '',
          });
          data.LatestMessInfo.unReadMessCou = 0;
        }
      )
    },
    // 请求详细的消息记录(第二次或以上的请求)
    async getPartMessages(payload: { userId: string; messageId: string }): Promise<number> {
      return await $axios(
        ['/messages/getPartMessages', 'post', payload, true],
        ({ messagesList, isLast }) => {
          const data = this.chatList.get(payload.userId)!;
          data.isLast = isLast;
          const beforeDatas = Array.from(data.messagesDatas!);
          const nowDatas: Array<[string, Message]> = Array.from(new Map(messagesList));
          beforeDatas.unshift(...nowDatas);
          data.messagesDatas = new Map(beforeDatas);
        }
      )
    },
    // 记录该登录用户准备和谁开始会话
    async setConversation(payload?: { selfId: string; otherId: string }): Promise<number> {
      return await $axios([
        '/messages/setConversation',
        'post',
        payload?.selfId ? { data: Base64.encode(JSON.stringify(payload)) } : undefined, true,
      ])
    },
    // 发送消息
    async sendMessage(payload: {
      selfId: string;
      otherId: string;
      content: string;
      imgs: Array<string>;
      id: string;
    }): Promise<number> {
      return await $axios([
        '/messages/sendMessage',
        'post',
        payload,
      ], () => {
        if (payload.imgs.length) this.isSendImg = true;
        else {
          const divEle = document.createElement('div');
          divEle.innerHTML = payload.content;
          const imgs = divEle.querySelectorAll('img');
          this.isSendImg = Array.from(imgs).some(item => item.dataset.key !== '表情');
        }
      })
    },
    // 发送录音消息
    sendRecordMessage(payload: {
      otherId: string;
      file: Blob,
      duration: number,
      id: string;
    }): Promise<number> {
      return new Promise<number>((resolve, reject) => {
        const formData = new FormData();
        formData.append("recorderFile", payload.file);
        formData.append("otherId", payload.otherId);
        formData.append("duration", payload.duration + "");
        fetch("/api/messages/record", {
          method: "post",
          body: formData,
        })
          .then((res) => res.json())
          .then((res) => {
            const { code, msg, data } = res;
            if (code === 1) {
              const chatDatas = this.chatList.get(payload.otherId);
              if (chatDatas) {
                const { userId, avatar, type, duration } = chatDatas.messagesDatas.get(payload.id)!;
                Object.assign(chatDatas.LatestMessInfo, {
                  latestMess: data.url,
                  messageId: data.messageId,
                  time: data.time,
                  type: 'voice',
                })
                chatDatas.messagesDatas.set(data.messageId, {
                  userId,
                  message: data.url,
                  time: data.time,
                  avatar,
                  type,
                  duration,
                  isLoading: false,
                });
                chatDatas.messagesDatas.delete(payload.id);
              }
            }
            else if (msg) console.log(msg);
            resolve(code);
          })
          .catch((error) => {
            console.log(error);
            reject();
          });
      })
    },
    // 删除某条消息
    async deleteMessage(
      key: string,
      payload: {
        selfId: string;
        otherId: string;
        messageId: Array<string>;
      },
    ): Promise<number> {
      return await $axios(
        [
          '/messages/deleteMessage',
          'post',
          {
            selfId: payload.selfId,
            otherId: payload.otherId,
            messageId: payload.messageId.filter(id => id.startsWith('001'))
          },
        ],
        ({ messageId }) => {
          const data = this.chatList.get(key);
          payload.messageId.forEach(id => data?.messagesDatas.delete(id));
          if (!messageId) {
            const time: number = new Date().getTime();
            Object.assign(data?.LatestMessInfo!, {
              time,
              messageId: '',
              latestMess: '',
            })
          }
          else if (data?.LatestMessInfo.messageId !== messageId) {
            const latestMess = data?.messagesDatas.get(messageId);
            if (latestMess)
              Object.assign(data?.LatestMessInfo!, {
                time: latestMess?.time,
                messageId,
                latestMess: latestMess.message,
                type: latestMess.type,
              });
            else {
              let count: number = 0;
              const timing = setInterval(() => {
                const latestMessData = data?.messagesDatas.get(messageId);
                if (latestMessData) {
                  Object.assign(data?.LatestMessInfo!, {
                    time: latestMessData.time,
                    messageId,
                    latestMess: latestMessData.message,
                    type: latestMessData.type,
                  });
                  clearInterval(timing);
                }
                count++;
                if (count === 420) clearInterval(timing);
              }, 50);
            }
          }
        }
      )
    },
    // 撤回某条消息
    async withdrawMessage(
      payload: {
        selfId: string;
        otherId: string;
        messageId: string;
      },
    ): Promise<number> {
      return await $axios(
        [
          '/messages/withdrawMessage',
          'post',
          payload,
        ],
      )
    },
    // 点击发送消息按钮准备发送消息(在搜索结果或者好友列表里面发送消息，前提是左边没有与该用户的会话窗口)
    async readySendMessage(
      payload: {
        selfId: string;
        otherId: string;
      },
    ): Promise<number> {
      return await $axios(
        [
          '/messages/readySendMessage',
          'post',
          payload,
        ],
        ({ value }) => {
          const chatList = Array.from(this.chatList);
          // 如果该窗口是非置顶的话
          if (!value.isTopping) {
            const index: number = chatList.findIndex(item => !item[1].LatestMessInfo.isTopping);
            chatList.splice(index, 0, [payload.otherId, {
              LatestMessInfo: value,
              messagesDatas: new Map(),
              isRequMessRecord: false,
              isNodisplayLoading: false,
              isToppingLoading: false,
            }])
          } else
            chatList.unshift([payload.otherId, {
              LatestMessInfo: value,
              messagesDatas: new Map(),
              isRequMessRecord: false,
              isNodisplayLoading: false,
              isToppingLoading: false,
            }])
          this.chatList = new Map(chatList);
        },
      )
    },
    // 不显示该聊天还是删除该聊天
    async operateTheChat(
      payload: {
        otherId: string;
        selfId: string;
        type: 'delete' | 'close',
      },
      callback: (...arg: any[]) => any,
    ): Promise<number> {
      const chatDatas = this.chatList.get(payload.otherId)!;
      if (payload.type === 'close') chatDatas.isNodisplayLoading = true;
      return new Promise<number>((resolve, reject) => {
        $axios(
          [
            '/messages/closeChat',
            'post',
            payload,
          ],
          () => {
            // 跳转回主页
            callback();
            setTimeout(() => this.chatList.delete(payload.otherId))
          }
        ).then((code: number) => {
          if (payload.type === 'close') chatDatas.isNodisplayLoading = false;
          resolve(code)
        }).catch(() => {
          if (payload.type === 'close') chatDatas.isNodisplayLoading = false;
          reject();
        })
      })
    },
    // 是否置顶该聊天
    async chatTopping(
      payload: {
        otherId: string;
        selfId: string;
      },
    ): Promise<number> {
      const chatDatas = this.chatList.get(payload.otherId)!;
      chatDatas.isToppingLoading = true;
      return new Promise<number>((resolve, reject) => {
        $axios(
          [
            '/messages/chatTopping',
            'patch',
            payload,
          ],
          () => {
            if (!chatDatas.LatestMessInfo.isTopping) {
              this.chatList.delete(payload.otherId);
              chatDatas.LatestMessInfo.isTopping = true;
              const chatList = Array.from(this.chatList);
              chatList.unshift([payload.otherId, chatDatas])
              this.chatList = new Map(chatList);
            } else chatDatas.LatestMessInfo.isTopping = false;
          },
        ).then(code => {
          chatDatas.isToppingLoading = false
          resolve(code)
        }).catch(() => {
          chatDatas.isToppingLoading = false;
          reject();
        });
      })
    },
    // 转发消息
    async forwardMessage(payload: {
      selfId: string;
      otherIds: Array<string>;
      messagesIds: Array<string>,
    }): Promise<number> {
      return new Promise<number>((resolve, reject) => {
        const noHavIds: Array<string> = [];
        payload.otherIds.forEach(id => !this.chatList.has(id) && noHavIds.push(id));
        if (noHavIds.length) {
          const axiosFun: Promise<number>[] = [];
          noHavIds.forEach(id => axiosFun.push(
            this.readySendMessage({ selfId: payload.selfId, otherId: id })
          ));
          Promise.all(axiosFun).then(codes => {
            if (codes.every((code) => code === 1)) $axios([
              '/messages/forwardMessage',
              'post',
              payload,
            ]).then(code => resolve(code)).catch(() => reject())
            else resolve(-1);
          }).catch(() => reject())
        } else
          $axios([
            '/messages/forwardMessage',
            'post',
            payload,
          ]).then(code => resolve(code)).catch(() => reject())
      })
    },
  },
})